home *** CD-ROM | disk | FTP | other *** search
- #include <stdio.h>
- #include <errno.h>
- #include <sys/time.h>
- #include <ctype.h>
- #include <strings.h>
-
- #include <sys/types.h>
- #include <sys/param.h>
- #include <sys/socket.h>
- #include <sys/file.h>
-
- #ifdef ISI4_2
- #include <netdb.h-bind>
- #else
- #include <netdb.h>
- #endif
-
- #include <netinet/in.h>
- #include <arpa/telnet.h>
-
- #include "fts.h"
- /* bftp.h is included in fts.h */
-
- boolean conference = FALSE;
- FILE *tracefp = NULL, /* File to save trace of Telnet history */
- *logfp = NULL; /* File to compose message */
-
- extern int errno;
- extern char *sys_errlist[] ;
-
- #define endof(x) (x + strlen(x))
- #define ToLower(ch) ( islower(ch)? ch:tolower(ch) )
- #define ToUpper(ch) ( isupper(ch)? ch:toupper(ch) )
-
- char *disposition[] =
- {"SUCCEEDED!",
- "FAILED BUT CAN RETRY",
- "FAILED PERMANENTLY",
- "!!SYSTEM ERROR"
- } ;
-
- /*
- * substr -- return pointer to sub-string in string
- * First check for an exact match; if one is not found,
- * check for a case-independent match.
- */
- char *
- substr (sb, sbSub)
- char *sb;
- char *sbSub;
- {
- char *pch;
- char *pchSub;
- char *pchStart = sb;
-
- while( *(pch = pchStart++) )
- {
- for( pchSub = sbSub; (*pch && *pchSub); )
- if( *pch++ != *pchSub++ )
- goto mismatch;
- if( !(*pchSub) )
- return (pchStart-1);
- mismatch: ;
- }
- pchStart = sb;
- while( *(pch = pchStart++) )
- {
- for( pchSub = sbSub; (*pch && *pchSub); ) {
- if( ToLower(*pch) != ToLower(*pchSub) )
- goto mismatch2;
- pch++;
- pchSub++;
- }
- if( !(*pchSub) )
- return (pchStart-1);
- mismatch2: ;
- }
- return (NULL);
- } /* substr */
-
- lookuphost(SH)
- SHandle SH;
- {
- if (SH) {
- SH->hostcount = resolve_name(SH->h.host, SH->inetaddr, MAX_addrs);
- if (!SH->hostcount ) {
- fprintf(logfp, "Unknown host: %s\n", SH->h.host);
- return(ERR_RETRY);
- }
- SH->addrcurr = 0;
- }
- return(OK);
- } /* lookuphost */
-
- /*
- * return = xfer(Source-SH, Destination-SH)
- */
- int
- xfer(ssh, dsh, fptr, reqfile, listfile)
- SHandle ssh, dsh;
- struct fileinfo *fptr;
- char *reqfile, *listfile;
- {
- int retcode;
- struct sockaddr_in myctladdr;
-
- /* tracefp = stdout; */
- /* tracefp = logfp; */
- if (ssh) ssh->socket = -1;
- if (dsh) dsh->socket = -1;
-
- if ( (OK != (retcode = lookuphost(ssh))) ||
- (OK != (retcode = lookuphost(dsh))) ||
- (OK != (retcode = openconn(ssh, &myctladdr))) ||
- (OK != (retcode = openconn(dsh, &myctladdr))) ||
- (OK != (retcode = login(ssh))) ||
- (OK != (retcode = login(dsh))) ||
- (OK != (retcode = TransferTo(ssh, dsh, fptr,
- reqfile, listfile,
- &myctladdr)))) {
-
- fprintf(logfp, "\nStatus: %s\n\n",
- disposition[-1 * retcode]);
- fflush(logfp);
- }
- closeconn(ssh);
- closeconn(dsh);
- return(retcode);
- } /* xfer */
-
- int
- data_listen(SH, myctladdr, data)
- register SHandle SH;
- struct sockaddr_in *myctladdr;
- int *data;
- {
- register char *p, *a;
- struct sockaddr_in data_addr;
- int len = sizeof(data_addr),
- code; /* return from getreply */
- char replybuf[MAXreply+1]; /* Text of last FTP reply message */
-
- if (! SH)
- return(OK);
-
- /* Set up the socket address structure */
- bcopy((char *)myctladdr, (char *)&data_addr, len);
-
- data_addr.sin_port = 0;
-
- /* Open TCP connection... */
- *data = socket(AF_INET, SOCK_STREAM, 0, 0);
- if (*data < 0) {
- serror(SH, "FTS: data socket");
- return(ERR_SYSTEM);
- }
- if (bind(*data, (char *)&data_addr, sizeof (data_addr)) < 0) {
- serror(SH, "FTS: data bind");
- close(*data);
- return(ERR_SYSTEM);
- }
- if (getsockname(*data, (char *)&data_addr, &len) < 0) {
- serror(SH, "FTS: data getsockname");
- close(*data);
- return(ERR_SYSTEM);
- }
- if (listen(*data, 1) < 0) {
- serror(SH, "FTS: data listen");
- close(*data);
- return(ERR_SYSTEM);
- }
-
- a = (char *)&data_addr.sin_addr;
- p = (char *)&data_addr.sin_port;
- #define UC(b) (((int)b)&0xff)
-
- if (REP_OK != (code = command(SH, replybuf, "PORT %d,%d,%d,%d,%d,%d",
- UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
- UC(p[0]), UC(p[1]))))
- close(*data);
-
- return(msgifreq("PORT error", code, SH, replybuf));
- } /* data_listen */
-
- int
- data_accept(SH, data, d_fpin)
- register SHandle SH;
- int *data;
- FILE **d_fpin;
- {
- FILE *fdopen();
- struct sockaddr_in from;
- int s, fromlen = sizeof (from);
-
- s = accept(*data, &from, &fromlen, 0);
- if (s < 0) {
- serror(SH, "FTS: data accept");
- close(*data);
- return(ERR_SYSTEM);
- }
- *data = s;
-
- /* Open input stream... */
- if ((*d_fpin = fdopen(*data, "r")) == NULL) {
- serror(SH, "FTS: data fdopen");
- close(*data);
- return(ERR_SYSTEM);
- }
- return(OK);
- } /* data_accept */
-
- data_close(data, d_fpin)
- int data;
- FILE *d_fpin;
- {
- int c;
-
- if (d_fpin) {
- /* Read to end of file */
- while ((c = getc(d_fpin)) != EOF) {
- if (tracefp)
- fprintf(tracefp,"%c", (char) c);
- }
-
- /* close connection */
- fclose(d_fpin);
- }
- close(data);
- } /* data_close */
-
- /*
- * result = openconn(SHandle)
- *
- * Open a TELNET connection to host specified in server-structure.
- * Returns OK if it succeeds (socket, fpin, and fpout will be set).
- */
-
- int
- openconn(SH, myctladdr)
- register SHandle SH;
- struct sockaddr_in *myctladdr;
- {
- struct sockaddr_in remote;
- int sock, len = sizeof (struct sockaddr_in);
-
- FILE *fdopen();
-
- char replybuf[MAXreply+1]; /* Text of last FTP reply message */
-
- if (! SH)
- return(OK);
- else {
- fprintf(logfp,"Connect to: %s, %d\n", SH->h.host, SH->h.port);
- fflush(logfp);
-
- /* Set up the socket address structure */
- bzero((char *)&remote, sizeof(struct sockaddr_in));
- remote.sin_family = AF_INET;
- bcopy((char *) &SH->inetaddr[SH->addrcurr],
- (char *) &remote.sin_addr, sizeof(struct in_addr));
- remote.sin_port = htons(SH->h.port);
-
- SH->socket = sock = socket(AF_INET, SOCK_STREAM, 0, 0);
- if (sock < 0) {
- serror(SH, "FTS: socket");
- return(ERR_SYSTEM);
- }
-
- /* Open TCP connection... */
- if (connect(sock, (struct sockaddr *) &remote, sizeof(remote)) < 0) {
- close(sock);
- SH->socket = -1;
- serror(SH, "FTS: TELNET connection failed");
- return((errno == ETIMEDOUT) ? ERR_RETRY :
- (errno == ECONNREFUSED) ? ERR_RETRY :
- (errno == ENETUNREACH) ? ERR_RETRY :
- ERR_SYSTEM);
- }
-
- if (getsockname(sock, (char *)myctladdr, &len) < 0) {
- serror(SH, "FTS: getsockname failed");
- close(sock);
- SH->socket = -1;
- return(ERR_SYSTEM);
- }
-
- /* Open input and output streams... */
- SH->fpin = NULL;
- if ( ((SH->fpin = fdopen(sock, "r")) == NULL) ||
- ((SH->fpout = fdopen(sock, "w")) == NULL)) {
- if (SH->fpin)
- fclose(SH->fpin);
- serror(SH, "FTS: fdopen");
- close(sock);
- SH->socket = -1;
- return(ERR_SYSTEM);
- }
-
- /* Get connection greeting message */
- if (REP_OK == getreply(SH, replybuf))
- return(OK);
- else
- return(ERR_RETRY);
- }
- } /* openconn */
-
-
- /*
- * closeconn(SHandle)
- *
- * Close TELNET connection to FTP Server (gently)
- */
- closeconn(SH)
- SHandle SH;
- {
- if (SH) {
- if (SH->socket < 0) return; /* not open */
- if (SH->fpout) {
- sendcmd(SH, "QUIT");
- fclose(SH->fpout);
- }
- fclose(SH->fpin);
- close(SH->socket);
- SH->socket = -1;
- }
- } /* closeconn */
-
-
- /*
- * result = login(SHandle)
- *
- * Given open TELNET connection, do login to FTP Server.
- * Returns OK if it succeeds, or else one of:
- * ERR_PERMANENT, ERR_RETRY, or ERR_SYSTEM.
- *
- */
- int
- login(SH)
- SHandle SH;
- {
- int code; /* return from getreply */
- char replybuf[MAXreply+1]; /* Text of last FTP reply message */
-
- if (! SH)
- return(OK);
-
- if (SH->socket < 0) {
- tellerr(SH, "CONN NOT OPEN FOR LOGIN");
- return(ERR_SYSTEM);
- }
-
- fprintf(logfp,"Logging in: %s, on %s\n", SH->h.user, SH->h.host);
- fflush(logfp);
-
- if (REP_NEEDMORE == (code = command(SH, replybuf, "USER %s", SH->h.user)))
- if (!strlen(SH->h.passwd)) {
- tellerr(SH, "Need password, none supplied");
- return(ERR_PERMANENT);
- }
- else if (REP_NEEDMORE == (code = command(SH, replybuf, "PASS %s", SH->h.passwd) ) )
- if (!strlen(SH->h.acct)) {
- tellerr(SH, "Need account, none supplied");
- return(ERR_PERMANENT);
- }
- else
- code = command(SH, replybuf, "ACCT %s", SH->h.acct);
-
- return(msgifreq("Login failure", code, SH, replybuf));
- } /* login */
-
- char
- scan_system(cp)
- char *cp;
- {
- if (! strncmp(cp, "UNIX", 4))
- return('/');
- else if (! strncmp(cp, "TOPS20", 6))
- return(':');
- else return('\0');
- }
-
- /*
- * result = TransferTo(Shandle1, Shandle2)
- *
- * Given two servers, each logged in, transfer file from 1 to 2.
- * Returns OK if it succeeds, or else one of:
- * ERR_PERMANENT, ERR_RETRY, or ERR_SYSTEM.
- *
- */
- #define MAXpsave 48 /* max len(A1,A2,A3,A4,a1,a2) */
- int
- TransferTo(SH1, SH2, f, reqfile, filelist, myctladdr)
- SHandle SH1, SH2;
- struct fileinfo *f;
- char *reqfile, *filelist;
- struct sockaddr_in *myctladdr;
- {
- FILE *listp,
- *d_fpin = NULL; /* File for data connection (NLST) */
-
- int data, /* Socket for TCP data connection */
- code1, code2,
- count, dir_count, dir_len,
- skip, i, cInt;
- char replybuf[MAXreply+1], /* Text of last FTP reply message */
- tycmd[20], filename[100],
- file1[50], file2[50], *cp,
- port_save[MAXpsave+1],
- temp[100], listfile[100], c;
- SHandle sh;
-
- boolean sh1_pasv,
- found_dir = FALSE,
- srcCWDfailed = FALSE,
- dstCWDfailed = FALSE;
-
- if (filelist)
- strcpy(listfile, filelist);
- else
- listfile[0] = '\0';
-
- for (sh = SH1; sh; sh = (sh == SH1) ? SH2: NULL) {
- if (dir_len = strlen(sh->h.dir)) {
- sprintf(tycmd,"CWD %s",sh->h.dir);
- /* fail temporarily if it timed out */
- if (REP_TIMEOUT == (code1 = command(sh, replybuf, tycmd)))
- return(msgifreq("CWD failed -- timeout", code1, sh, replybuf));
-
- /* if we are already in the "pub" directory,
- if first part of directory is "pub",
- strip it off and try again
- else
- try going up one level and try cwd again */
- if (REP_OK != code1) {
- /* find out if we are in "pub/" now */
- if (REP_TIMEOUT == (code1 = command(sh, replybuf, "PWD")))
- return(msgifreq("PWD failed -- timeout", code1, sh, replybuf));
- else
- if (REP_OK == code1 && !strncmp(replybuf+4, "\"/pub", 5))
- /* we are in "pub"; is that what we wanted? */
- if (dir_len > 3 &&
- !strncmp(sh->h.dir, "pub/",(dir_len>3)?4:3))
- if (dir_len>4) {
- sprintf(tycmd,"CWD %s",sh->h.dir+4);
- if (REP_TIMEOUT == (code1 =
- command(sh, replybuf, tycmd)))
- return(msgifreq("CWD failed -- timeout",
- code1, sh, replybuf));
- }
- else
- code1 = REP_OK;
- else {
- /* try going up one level */
- sprintf(tycmd,"CWD ../%s",sh->h.dir);
- if (REP_TIMEOUT == (code1 = command(sh, replybuf, tycmd)))
- return(msgifreq("CWD failed -- timeout",
- code1, sh, replybuf));
- }
- else
- code1 = REP_PERMERR;
- }
- /* get the directory delimiter if needed */
- if (REP_OK != code1 || (f->multflag && sh == SH2))
- if (strlen(sh->h.dir) &&
- ispunct(sh->h.dir[strlen(sh->h.dir)-1]) &&
- sh->h.dir[strlen(sh->h.dir)-1] != '*')
- sh->dir_delim = sh->h.dir[strlen(sh->h.dir)-1];
- else
- if (REP_OK != (command(sh, replybuf, "SYST")) ||
- !(sh->dir_delim = scan_system(replybuf+4)))
- sh->dir_delim = '\0';
- else {
- sh->h.dir[strlen(sh->h.dir)] = sh->dir_delim;
- sh->h.dir[strlen(sh->h.dir)] = '\0';
- }
-
- if (REP_OK != code1) {
- /* if last char of dir != punc then fail-perm */
- if (! sh->dir_delim) {
- return(msgifreq(
- "CWD failed -- directory delimiter not known",
- REP_PERMERR, sh, replybuf));
- }
- if (sh == SH1)
- srcCWDfailed = TRUE;
- else
- dstCWDfailed = TRUE;
- }
- }
- } /* for */
-
- /* *** if both ends are "UNIX Type: L8" go into image mode. */
-
- /* get list of file names from source host */
- if (srcCWDfailed) {
- strcpy(file1, SH1->h.dir);
- strcat(file1, SH1->h.file);
- }
- else
- strcpy(file1, SH1->h.file);
-
- if (!strlen(listfile)) {
- strcpy(listfile, reqfile);
- strcpy(endof(listfile)-3,"list");
- if (tracefp) {
- fprintf(tracefp,"Creating '%s' list-file\n", listfile);
- fflush(tracefp);
- }
- listp = fopen(listfile, "w");
- sprintf(temp,"%5d\n",0); /* write out number entries to skip */
- fputs(temp, listp);
-
- if (!f->multflag && (f->reqtype!=VERIFY) && (f->reqtype!=VERIFY_SRC)) {
- fputs(file1, listp);
- if (conference) {
- fputc('\n', listp);
- name_dotfile(file1, temp);
- fputs(temp, listp); /* put in name of dot-file */
- }
- }
- else { /* Use NLST to get list */
- if ((code1 = data_listen(SH1, myctladdr, &data)) != OK) {
- fclose(listp);
- return(code1);
- }
- if ((code1 = command(SH1, replybuf, "NLST %s", file1)) != REP_PRELIM &&
- code1 != REP_OK) {
- fclose(listp);
- data_close(data, d_fpin);
- return(msgifreq("NLST error", code1, SH1, replybuf));
- }
- if ((code2 = data_accept(SH1, &data, &d_fpin)) != OK)
- return(code2);
-
- cp = filename;
- while ((cInt = getc(d_fpin)) != EOF) {
- c = cInt;
- if (c != '\015') {
- putc(c,listp);
- /* debugging fprintf(logfp,"%c",c); */
- if (c != '\n')
- *cp++ = c;
- }
- else {
- *cp = '\0';
- if (conference) {
- fputc('\n', listp);
- name_dotfile(filename, temp);
- fputs(temp, listp); /* put in name of dot-file */
- /* debugging printf("-->%s %s\n",filename, temp); */
- }
- cp = filename;
- }
- }
- data_close(data, d_fpin);
- while (code1==REP_PRELIM) code1 = getreply(SH1, replybuf);
- if (code1 == REP_PERMERR) {
- fclose(listp);
- return(msgifreq("NLST error", code1, SH1, replybuf));
- }
- }
- fclose(listp);
- } /* if (!strlen(listfile)) */
-
- for (sh = SH1; sh; sh = (sh == SH1) ? SH2: NULL) {
- /* Send type setup commands to each side of connection. */
- if (sh->socket < 0) {
- tellerr(sh, "CONN NOT OPEN FOR TRANSFER");
- return(ERR_SYSTEM);
- }
- if ((f->reqtype != DFILE) && (f->reqtype != VERIFY_SRC)) {
- if (f->stru != 'F') {
- sprintf(tycmd,"STRU %c",f->stru);
- if (REP_OK != (code1 = command(sh, replybuf, tycmd) ))
- return(msgifreq("Host does not support stru", code1, sh, replybuf));
- }
- /* note different default for (f->stru == 'P') */
- if ((f->mode != 'S') || (f->stru == 'P')) {
- sprintf(tycmd,"MODE %c",f->mode);
- if (REP_OK != (code1 = command(sh, replybuf, tycmd) ))
- return(msgifreq("Host does not support mode", code1, sh, replybuf));
- }
- if ((strcmp(f->filetype,"A N")!=0) || (f->stru == 'P')) {
- sprintf(tycmd,"TYPE %s",f->filetype);
- if (REP_OK != (code1 = command(sh, replybuf, tycmd) ))
- return(msgifreq("Host does not support file type", code1, sh, replybuf));
- }
- }
- } /* for */
-
-
- /* Not all hosts support PASV; try one & if it fails try the other. */
- #ifdef DST_FIRST
- sh = SH2;
- sh1_pasv = FALSE;
- #else
- sh = SH1;
- sh1_pasv = TRUE;
- #endif
- if (REP_PERMERR == (code1 = command(sh, replybuf, "PASV")) ) {
- /* it failed permanently, so try the other end */
- if (sh1_pasv) {
- sh = SH2;
- sh1_pasv = FALSE;
- }
- else {
- sh = SH1;
- sh1_pasv = TRUE;
- }
- if (REP_PERMERR == (code1 = command(sh, replybuf, "PASV")) )
- return(msgifreq("Neither host supports PASV", code1, sh, replybuf));
- }
- if (code1 != REP_OK)
- return(msgifreq("Temporary error in PASV", code1, sh, replybuf));
-
- if (! scan_port(port_save, MAXpsave, &replybuf[5])) {
- reply_err("Malformed PASV reply", sh, replybuf);
- return(ERR_PERMANENT);
- }
-
- if ((f->reqtype == COPY) || (f->reqtype == MOVE)) {
- /* Send PORT command to other host */
- sh = (sh1_pasv)? SH2 : SH1;
- if (REP_OK != (code1 = command(sh, replybuf, "PORT %s", port_save)) )
- return(msgifreq("PORT error", code1, sh, replybuf));
- }
-
- /* get list of files */
- listp = fopen(listfile, "r+");
- if (listp == NULL) {
- tellerr(SH1,"Can't find list of remote files.");
- return(ERR_PERMANENT);
- }
- /* read number of files to skip */
- fgets(filename, sizeof(filename), listp);
- if (skip = atoi(filename)) {
- skip--; /* otherwise diskless hosts may be missing part of last file */
- if (skip && tracefp)
- fprintf(tracefp,"Skipping %d file(s).\n", skip);
- }
-
- /* write out number of entries to skip */
- #define save_skip() {rewind(listp); \
- sprintf(temp,"%5d\n",count-1); \
- fputs(temp, listp); \
- fclose(listp);\
- if (filelist && !strlen(filelist))\
- strcpy(filelist, listfile);}
-
- count = 0;
- found_dir = FALSE;
- while (fgets(filename, sizeof(filename), listp) != NULL) {
- /* loop on each file name */
- if ((cp = index(filename, '\n')) != NULL)
- *cp = '\0';
-
- /* check for BSD directory notation */
- if ((!strlen(filename)) || (index(filename, ' ')) ||
- (filename[strlen(filename)-1] == ':')) {
- found_dir = TRUE;
- break;
- }
- count++;
-
- /* munge file names */
- strcpy(file1, filename);
- if ((f->reqtype != VERIFY_SRC) && (f->reqtype != DFILE)) {
- strcpy(file2, (dstCWDfailed)? SH2->h.dir : "");
- strcat(file2, ((!strlen(SH2->h.file)) ||
- (f->multflag && (f->creation != APPE))||
- (conference && count>1))?
- filename : SH2->h.file);
- }
-
- if (((f->reqtype == COPY) && (count > skip)) ||
- (f->reqtype == MOVE)) {
- fprintf(logfp, "Transferring %s\n", file1);
- fflush(logfp);
- if (count != 1) {
- sh = (sh1_pasv)? SH1:SH2;
- if (REP_OK != (code1 = command(sh, replybuf, "PASV"))) {
- save_skip();
- return(msgifreq("PASV command failed", code1, sh, replybuf));
- }
- if (! scan_port(port_save, MAXpsave, &replybuf[5])) {
- fclose(listp);
- reply_err("Malformed PASV reply", sh, replybuf);
- return(ERR_PERMANENT);
- }
- sh = (sh1_pasv)? SH2:SH1;
- if (REP_OK != (code1 = command(sh, replybuf,
- "PORT %s", port_save) )) {
- save_skip();
- return(msgifreq("PORT error", code1, sh, replybuf));
- }
- }
-
- /* Now open the DT connection(s) */
- /* STOR, 5 second pause, RETR -- For the TOPS-20s */
-
- sendcmd(SH2, "%s %s", (f->creation==APPE)?"APPE":
- (f->creation==STOU)?"STOU":
- "STOR",
- file2);
- sleep(5);
- sendcmd(SH1, "RETR %s", file1);
-
- code1 = code2 = REP_PRELIM;
- while ((code1<=REP_PRELIM)||(code2<=REP_PRELIM)) {
- sh = SH1;
- if (code1<=REP_PRELIM) code1 = getreply(SH1, replybuf);
- if ((code1==REP_PERMERR) || (code1==REP_TEMPERR)) break;
- sh = SH2;
- if (code2<=REP_PRELIM) code2 = getreply(SH2, replybuf);
- if ((code2==REP_PERMERR) || (code2==REP_TEMPERR)) break;
- }
- if (code1 != REP_OK || code2 != REP_OK) {
- if (!tracefp)
- fprintf(logfp," %s ==> %s\n", sh->h.host, replybuf);
- if ((conference || f->multflag) &&
- (code1 == REP_PERMERR || code2 == REP_PERMERR)) {
- if (f->multflag && code1 <= REP_PRELIM && SH2->dir_delim) {
- for (i = strlen(file1)-1; i ; i--)
- if (file1[i] == SH2->dir_delim) break;
- if (i) {
- strncpy(temp, file1,
- (SH2->dir_delim == '/')? i: i+1);
- if (REP_OK == (code2 = command(SH2, replybuf,"MKD %s",temp)) ||
- REP_OK == (code2 = command(SH2, replybuf,"XMKD %s",temp))) {
- code2 = REP_PRELIM;
- sendcmd(SH2, "%s %s",
- (f->creation==APPE)?"APPE":
- (f->creation==STOU)?"STOU": "STOR",
- file2);
- while ((code1<=REP_PRELIM)||
- (code2<=REP_PRELIM)) {
- if (code1<=REP_PRELIM)
- code1 = getreply(SH1, replybuf);
- if ((code1==REP_PERMERR) ||
- (code1==REP_TEMPERR))
- break;
- if (code2<=REP_PRELIM)
- code2 = getreply(SH2, replybuf);
- if ((code2==REP_PERMERR) ||
- (code2==REP_TEMPERR))
- break;
- }
- }
- }
- if (code1 != REP_OK || code2 != REP_OK)
- if (! sendabort(SH1)) {
- count += 2;
- save_skip();
- return(ERR_RETRY);
- }
- }
- else if (code2 <= REP_PRELIM) {
- if (! sendabort(SH2)) {
- count += 2;
- save_skip();
- return(ERR_RETRY);
- }
- }
- }
- else {
- save_skip();
- return( (code1==REP_PERMERR || code2==REP_PERMERR)
- ? ERR_PERMANENT :
- ERR_RETRY );
- }
- }
- }
- else if ((f->reqtype == VERIFY) || (f->reqtype == VERIFY_SRC)) {
- if ((! f->multflag) && (substr(filename, SH1->h.file)==NULL)) {
- tellerr(SH1,
- "Source file \'%s\' not found -- %swildcard matching.",
- SH1->h.file, (f->multflag) ? NULL : "NO ");
- fclose(listp); /* no skipping in this case */
- return(ERR_PERMANENT);
- }
- if (count == 1)
- fprintf(logfp,"Matching file names:\n");
- fprintf(logfp," %s\n", file1);
- }
- if ((f->reqtype == DFILE) || (f->reqtype == MOVE)) {
- fprintf(logfp, "Deleting %s.\n", file1);
- code1 = REP_PRELIM;
- sendcmd(SH1, "DELE %s", file1);
- while (code1==REP_PRELIM) code1 = getreply(SH1, replybuf);
- if (code1 != REP_OK) {
- fclose(listp); /* no skipping in this case */
- return(msgifreq("DELE error", code1, SH1, replybuf));
- }
- }
- } /* while */
- fflush(logfp);
-
- if (found_dir && f->multflag &&
- ((f->reqtype == VERIFY) || (f->reqtype == VERIFY_SRC))) {
- dir_count = 0;
- rewind(listp);
- while (fgets(filename, sizeof(filename), listp) != NULL)
- { /* loop on each file name */
- if ((cp = index(filename, '\n')) != NULL)
- *cp = '\0';
-
- /* check for BSD directory notation */
- if (index(filename, ':')) {
- if (!dir_count)
- fprintf(logfp,"Matching directory:\n");
- fprintf(logfp," %s\n",filename);
- dir_count++;
- }
- }
- }
- fclose(listp);
-
- if (!count) {
- tellerr(SH1,"Source file \'%s\' not found.", file1);
- return(ERR_PERMANENT);
- }
- fflush(logfp);
- return(OK);
-
- } /* TransferTo */
-
- /*
- * sendcmd(SHandle, format, arg1, arg2, ...)
- *
- * Format command string and send to specified host.
- *
- */
- sendcmd(SH, format, arg1, arg2, arg3, arg4, arg5, arg6)
- SHandle SH;
- char *format;
- {
- char cmdbuff[256];
- if (SH) {
- sprintf(cmdbuff, format, arg1, arg2, arg3, arg4, arg5, arg6);
- if (tracefp) {
- fprintf(tracefp, " %s <== %s\n", SH->h.host,
- (strncmp(format,"PASS",4) == 0)? "PASS XXX": cmdbuff);
- fflush(tracefp);
- }
- fputs(cmdbuff, SH->fpout);
- fputs("\r\n", SH->fpout);
- fflush(SH->fpout);
- }
- } /* sendcmd */
-
- int
- sendabort(SH)
- SHandle SH;
- {
- int temp1, temp2;
- char msg[2];
-
- char replybuf[MAXreply+1]; /* Text of last FTP reply message */
-
- fprintf(SH->fpout,"%c%c",IAC,IP);
- (void) fflush(SH->fpout);
- *msg = IAC;
- *(msg+1) = DM;
- if (send(fileno(SH->fpout),msg,2,MSG_OOB) != 2)
- perror("abort");
-
- /* get the reply to the previous command and the reply to the ABORT */
- temp1 = command(SH, replybuf,"ABOR");
- temp2 = getreply(SH, replybuf);
- return((temp1 && temp1 != REP_PERMERR &&
- temp2 != REP_PERMERR)? TRUE: FALSE);
- }
-
- /*
- * result = command(SHandle, format, arg1, arg2, ...)
- *
- * Format command string and send to specified host, and then
- * call getreply() and return result code.
- *
- */
- int
- command(SH, ptr, format, arg1, arg2, arg3, arg4, arg5, arg6)
- SHandle SH;
- char *ptr, *format;
- {
- if (SH) {
- sendcmd(SH, format, arg1, arg2, arg3, arg4, arg5, arg6);
- return(getreply(SH, ptr));
- }
- else return(REP_PERMERR);
- } /* command */
-
-
- /*
- * int = getreply(SHandle)
- *
- * Receive next reply message from remote host, and return binary
- * value of reply number as result. Actual text is stored in global
- * array reply_text.
- *
- * This routine waits for first reply, then if more input is buffered
- * in the kernel it gets the next reply. It returns only the last
- * complete reply when no more input is buffered.
- *
- */
-
- int
- getreply(SH, ptr)
- SHandle SH;
- char *ptr;
- {
- register char c;
- int firstdigit, n, cInt;
- register char *cp = ptr;
- register int cpcnt = MAXreply;
- char *startline, *tmp;
-
- *ptr = '\0';
-
- for (;;) { /* Loop through one line of reply... */
- /* time out and return 0 after N seconds */
- for (n = 0; n < FTPTIMEOUT; n++) {
- if (! empty(SH->fpin)) break;
- sleep(1);
- }
- if (n >= FTPTIMEOUT)
- return(REP_TIMEOUT);
-
- startline = cp;
- while ((cInt = getc(SH->fpin)) != '\n') {
- if (cInt == EOF) {
- fprintf(logfp, "Host %s closed Conn\n", SH->h.host);
- return(REP_TEMPERR);
- }
- c = cInt;
- if (cpcnt == MAXreply) {
- if (!isdigit(c)) {
- /* Syntax error... reply does not begin with digit!! */
- /* Invent code 599 for the text... */
- strcpy(ptr, "599 ");
- cpcnt -= 4;
- cp += 4;
- firstdigit = 5;
- }
- else
- firstdigit = c - '0';
- }
-
- if ((c != '\r') && (--cpcnt > 0)) *cp++ = c;
- }
-
- *cp = '\0';
- if (tracefp) {
- fprintf(tracefp, " %s ==> %s\n", SH->h.host, startline);
- fflush(tracefp);
- }
-
- /* End of line. Test for continuation... */
- tmp = ptr+3;
- if ((*tmp != '-') ||
- (startline[3] != '-' &&
- (strncmp(ptr, startline, 3) == 0)) ) {
- /* Have complete reply. But if there is more input
- * buffered, start over... */
- if (empty(SH->fpin)) {
- return(firstdigit);
- }
-
- cp = ptr;
- cpcnt = MAXreply;
- }
-
- }
- } /* getreply */
-
- /*
- * boolean empty(FILE *)
- *
- * Based on routine from User FTP from 4.2BSD.
- */
- fd_select(fd)
- int fd;
- {
- int fd_width = getdtablesize();
-
- #ifdef BSD4_3
- fd_set mask, dummy;
- #else
- long mask = (1 << fd),
- dummy = 0;
- #endif
-
- struct timeval t;
- int i;
-
- #ifdef BSD4_3
- FD_ZERO(&mask);
- FD_SET(fd, &mask);
- FD_ZERO(&dummy);
- #endif
-
- t.tv_sec = t.tv_usec = 0;
- if (fd > fd_width) {
- fprintf(stderr, "Error: maximum fd count (%d) exceeded.\n",fd_width);
- return(0); /* assume that it is empty */
- }
- if ((i = select(fd_width, &mask, &dummy, &dummy, &t)) == -1) {
- perror("fts: Select error");
- return(1); /* assume that it is not empty */
- }
- return(i);
- }
-
- empty(f)
- FILE *f;
- {
- if (f->_cnt > 0)
- return (0);
- return((fd_select(fileno(f)) == 0)? TRUE: FALSE);
- } /* empty */
-
- boolean
- scan_port(pp, maxlen, ptr)
- /* Scan reply for port parameters */
- char *pp;
- int maxlen;
- char *ptr;
- {
- char *cp, *start, digit[2];
- int n, totlen, params;
-
- /* Position cp on first digit */
- for (cp = ptr; (*cp) && !isdigit(*cp); cp++ ) ;
- start = cp;
- n = 0;
- for (totlen=0 ; ; cp++, totlen++) {
- if ((! *cp) || *cp == ')' || *cp == ',' || *cp == ' ') {
- if (n > 255)
- return(FALSE);
- else
- n = 0;
- }
- else {
- strncpy(digit, cp, 1);
- digit[1] = '\0';
- if (isdigit(digit[0]))
- n = (n*10) + atoi(digit);
- else
- return(FALSE);
- }
- if ((! *cp) || *cp == ')')
- break;
- }
- if ((totlen==0) || (totlen >= maxlen))
- return(FALSE);
- else {
- strncpy(pp,start,totlen);
- *(pp+totlen) = '\0';
- return(TRUE);
- }
- } /* scan_port */
-
- /*
- * tellerr(Server-handle, format, arg1, arg2, ...)
- * -- Format error message associated with specified host
- */
-
- tellerr(SH, format, arg1, arg2, arg3, arg4)
- SHandle SH;
- char *format;
- {
- char temp[256];
- sprintf(temp, format, arg1, arg2, arg3, arg4);
-
- fprintf(logfp, "\n%s -- %s\n", SH->h.host, temp);
- }
-
-
- /*
- * serror(server-handle, string) -- like the system routine perror()
- */
-
- serror(SH, cp)
- SHandle SH;
- char *cp;
- {
- tellerr(SH, "%s: %s", cp, sys_errlist[errno]);
- }
-
- reply_err(msg, sh, reply)
- char *msg;
- SHandle sh;
- char *reply;
- {
- tellerr(sh, "%s\n\tError: %s", msg, reply);
- }
-
- int
- msgifreq(msg, code, sh, reply)
- char *msg;
- int code;
- SHandle sh;
- char *reply;
- {
- switch (code) {
- case REP_OK:
- return(OK);
- case REP_TIMEOUT:
- tellerr(sh, "FTP timeout");
- return(ERR_RETRY);
- case REP_PERMERR:
- reply_err(msg, sh, reply);
- return(ERR_PERMANENT);
- default:
- reply_err(msg, sh, reply);
- return(ERR_RETRY);
- }
- } /* msgifreq */
-